package com.sf.sms.user.auth;

import com.sf.sms.user.entity.Resources;
import com.sf.sms.user.entity.Role;
import com.sf.sms.user.entity.User;
import com.sf.sms.user.service.IMsResourcesBiz;
import com.sf.sms.user.service.IMsRoleBiz;
import com.sf.sms.user.service.IMsUserBiz;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created by 80002004 on 2016/7/18.
 */
@Component
public class AuthRealm extends IniRealm {

    Logger log = LoggerFactory.getLogger(this.getClass());
    @Resource
    private IMsResourcesBiz resourcesBiz;
    @Resource
    private IMsRoleBiz roleBiz;
    @Resource
    private IMsUserBiz userBiz;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();
        User user = (User) principals.getPrimaryPrincipal();

        List<Resources> resources = resourcesBiz.findUserResources(user.getId());
        List<Role> roles = roleBiz.findUserRoles(user.getId());
        user.setResources(resources);
        user.setRoles(roles);

        authInfo.setRoles(createRoles(roles));
        authInfo.setStringPermissions(createPermissions(resources));

        return  authInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authToken;
        User user = userBiz.findByName(token.getUsername());

        if(null != user) {

            SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();
            authInfo.setRoles(user.getRoles());
            authInfo.setStringPermissions(user.getResources());

            this.setAttr2Session("currentUser", user);

//            byte[] salt = Encodes.decodeHex(user.getSalt());
            return new SimpleAuthenticationInfo(user, user.getPassWord(), /*ByteSource.Util.bytes(salt), */user.getUserName());
        } else {
            throw new UnknownAccountException("No account found for user [" + token.getUsername() + "]");
        }
    }

    /**
     * 将用户信息保存到session中
     * @param key
     * @param value
     * void
     */
    private void setAttr2Session(Object key, Object value){
        Subject subject  = SecurityUtils.getSubject();
        if(subject != null){
            Session session = subject.getSession();
            if(session != null){
                session.setAttribute(key, value);
            }
        }
    }

    /**
     * 获取seesion中的值
     * @param key
     * @return
     */
    private Object getAttrFormSession(Object key){
        Subject subject  = SecurityUtils.getSubject();
        if(subject != null){
            Session session = subject.getSession();
            if(session != null){
                return session.getAttribute(key);
            }
        }
        return null;

    }

    /**
     * 获取权限资源Set集合
     * @param resources
     * @return
     */
    private Set<String> createPermissions(List<Resources> resources) {
        if(!CollectionUtils.isEmpty(resources)) {
            Set<String> pss = new HashSet<>();
            for(Resources r : resources) {
                pss.add(r.getResCode());
            }
            return pss;
        }
        return null;
    }

    /**
     * 获取角色Set集合
     * @param roles
     * @return
     */
    private Set<String> createRoles(List<Role> roles) {
        if(!CollectionUtils.isEmpty(roles)) {
            Set<String> rss = new HashSet<String>();
            for(Role r : roles) {
                rss.add(r.getRoleCode());
            }
            return rss;
        }
        return null;
    }

}
